home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 49
/
Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso
/
-serious-
/
graphics
/
gnuplot
/
gnuplot-3.7.1src
/
gnuplot-3.7.1
/
plot.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-11-29
|
18KB
|
727 lines
#ifndef lintuse free() insteSid = "$Id: plot.c,v 1.18.2.2 1999/09/23 13:26:36 lhecking Exp $";
#endif
/* GNUPLOT - plot.c */
/*[
* Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the complete modified source code. Modifications are to
* be distributed as patches to the released version. Permission to
* distribute binaries produced by compiling modified sources is granted,
* provided you
* 1. distribute the corresponding source modifications from the
* released version in the form of a patch file along with the binaries,
* 2. add special version identification to distinguish your version
* in addition to the base release version number,
* 3. provide your name and address as the primary contact for the
* support of your modified version, and
* 4. retain our contact information in regard to use of the base
* software.
* Permission to distribute the released version of the source code along
* with corresponding source modifications in the form of a patch file is
* granted with same provisions 2 through 4 for binary distributions.
*
* This software is provided "as is" without express or implied warranty
* to the extent permitted by applicable law.
]*/
#include <signal.h>
#include "plot.h"
#include "fit.h"
#include "setshow.h"
#include "fnproto.h"
#include <setjmp.h>
#if defined(MSDOS) || defined(DOS386) || defined(__EMX__)
# include <io.h>
#endif
/* HBB: for the control87 function, if used with DJGPP V1: */
#if defined(DJGPP) && (DJGPP!=2)
# include "ctrl87.h"
#endif
#ifdef VMS
# ifndef __GNUC__
# include <unixio.h>
# endif
# include <smgdef.h>
extern int vms_vkid;
extern smg$create_virtual_keyboard();
extern int vms_ktid;
extern smg$create_key_table();
#endif /* VMS */
#ifdef AMIGA_SC_6_1
# include <proto/dos.h>
#endif
#ifdef _Windows
# include <windows.h>
# ifndef SIGINT
# define SIGINT 2 /* for MSC */
# endif
#endif /* _Windows */
extern FILE *gpoutfile;
TBOOLEAN interactive = TRUE; /* FALSE if stdin not a terminal */
TBOOLEAN noinputfiles = TRUE; /* FALSE if there are script files */
/* these 2 could be in misc.c, but are here with all the other globals */
TBOOLEAN do_load_arg_substitution = FALSE;
char *call_args[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
char *infile_name = NULL; /* name of command file; NULL if terminal */
#ifdef HAVE_LIBREADLINE
extern char *rl_readline_name;
extern int rl_complete_with_tilde_expansion;
#endif
#ifdef X11
extern int X11_args __PROTO((int, char **));
#endif
/* patch to get home dir, see command.c */
#if (defined (__TURBOC__) && (defined (MSDOS) || defined(DOS386))) || defined(DJGPP)
# include <dir.h> /* MAXPATH */
char HelpFile[MAXPATH];
#endif /* - DJL */
#ifndef STDOUT
# define STDOUT 1
#endif
/* a longjmp buffer to get back to the command line */
#ifdef _Windows
static jmp_buf far command_line_env;
#else
static jmp_buf command_line_env;
#endif
static void load_rcfile __PROTO((void));
RETSIGTYPE inter __PROTO((int anint));
/* built-in function table */
struct ft_entry GPFAR ft[] =
{
/* internal functions: */
{"push", (FUNC_PTR) f_push},
{"pushc", (FUNC_PTR) f_pushc},
{"pushd1", (FUNC_PTR) f_pushd1},
{"pushd2", (FUNC_PTR) f_pushd2},
{"pushd", (FUNC_PTR) f_pushd},
{"call", (FUNC_PTR) f_call},
{"calln", (FUNC_PTR) f_calln},
{"lnot", (FUNC_PTR) f_lnot},
{"bnot", (FUNC_PTR) f_bnot},
{"uminus", (FUNC_PTR) f_uminus},
{"lor", (FUNC_PTR) f_lor},
{"land", (FUNC_PTR) f_land},
{"bor", (FUNC_PTR) f_bor},
{"xor", (FUNC_PTR) f_xor},
{"band", (FUNC_PTR) f_band},
{"eq", (FUNC_PTR) f_eq},
{"ne", (FUNC_PTR) f_ne},
{"gt", (FUNC_PTR) f_gt},
{"lt", (FUNC_PTR) f_lt},
{"ge", (FUNC_PTR) f_ge},
{"le", (FUNC_PTR) f_le},
{"plus", (FUNC_PTR) f_plus},
{"minus", (FUNC_PTR) f_minus},
{"mult", (FUNC_PTR) f_mult},
{"div", (FUNC_PTR) f_div},
{"mod", (FUNC_PTR) f_mod},
{"power", (FUNC_PTR) f_power},
{"factorial", (FUNC_PTR) f_factorial},
{"bool", (FUNC_PTR) f_bool},
{"dollars", (FUNC_PTR) f_dollars}, /* for using extension */
{"jump", (FUNC_PTR) f_jump},
{"jumpz", (FUNC_PTR) f_jumpz},
{"jumpnz", (FUNC_PTR) f_jumpnz},
{"jtern", (FUNC_PTR) f_jtern},
/* standard functions: */
{"real", (FUNC_PTR) f_real},
{"imag", (FUNC_PTR) f_imag},
{"arg", (FUNC_PTR) f_arg},
{"conjg", (FUNC_PTR) f_conjg},
{"sin", (FUNC_PTR) f_sin},
{"cos", (FUNC_PTR) f_cos},
{"tan", (FUNC_PTR) f_tan},
{"asin", (FUNC_PTR) f_asin},
{"acos", (FUNC_PTR) f_acos},
{"atan", (FUNC_PTR) f_atan},
{"atan2", (FUNC_PTR) f_atan2},
{"sinh", (FUNC_PTR) f_sinh},
{"cosh", (FUNC_PTR) f_cosh},
{"tanh", (FUNC_PTR) f_tanh},
{"int", (FUNC_PTR) f_int},
{"abs", (FUNC_PTR) f_abs},
{"sgn", (FUNC_PTR) f_sgn},
{"sqrt", (FUNC_PTR) f_sqrt},
{"exp", (FUNC_PTR) f_exp},
{"log10", (FUNC_PTR) f_log10},
{"log", (FUNC_PTR) f_log},
{"besj0", (FUNC_PTR) f_besj0},
{"besj1", (FUNC_PTR) f_besj1},
{"besy0", (FUNC_PTR) f_besy0},
{"besy1", (FUNC_PTR) f_besy1},
{"erf", (FUNC_PTR) f_erf},
{"erfc", (FUNC_PTR) f_erfc},
{"gamma", (FUNC_PTR) f_gamma},
{"lgamma", (FUNC_PTR) f_lgamma},
{"ibeta", (FUNC_PTR) f_ibeta},
{"igamma", (FUNC_PTR) f_igamma},
{"rand", (FUNC_PTR) f_rand},
{"floor", (FUNC_PTR) f_floor},
{"ceil", (FUNC_PTR) f_ceil},
{"norm", (FUNC_PTR) f_normal}, /* XXX-JG */
{"inverf", (FUNC_PTR) f_inverse_erf}, /* XXX-JG */
{"invnorm", (FUNC_PTR) f_inverse_normal}, /* XXX-JG */
{"asinh", (FUNC_PTR) f_asinh},
{"acosh", (FUNC_PTR) f_acosh},
{"atanh", (FUNC_PTR) f_atanh},
{"column", (FUNC_PTR) f_column}, /* for using */
{"valid", (FUNC_PTR) f_valid}, /* for using */
{"timecolumn", (FUNC_PTR) f_timecolumn}, /* for using */
{"tm_sec", (FUNC_PTR) f_tmsec}, /* for timeseries */
{"tm_min", (FUNC_PTR) f_tmmin}, /* for timeseries */
{"tm_hour", (FUNC_PTR) f_tmhour}, /* for timeseries */
{"tm_mday", (FUNC_PTR) f_tmmday}, /* for timeseries */
{"tm_mon", (FUNC_PTR) f_tmmon}, /* for timeseries */
{"tm_year", (FUNC_PTR) f_tmyear}, /* for timeseries */
{"tm_wday", (FUNC_PTR) f_tmwday}, /* for timeseries */
{"tm_yday", (FUNC_PTR) f_tmyday}, /* for timeseries */
{NULL, NULL}
};
static struct udvt_entry udv_pi = { NULL, "pi", FALSE };
/* first in linked list */
struct udvt_entry *first_udv = &udv_pi;
struct udft_entry *first_udf = NULL;
static int exit_status = EXIT_SUCCESS;
#ifdef OS2
# define INCL_DOS
# define INCL_REXXSAA
# include <os2.h>
# include <process.h>
ULONG RexxInterface(PRXSTRING, PUSHORT, PRXSTRING);
int ExecuteMacro(char *, int);
void PM_intc_cleanup();
void PM_setup();
#endif /* OS2 */
#if defined(ATARI) || defined(MTOS)
/* For findfile () (?) */
# include <support.h>
void appl_exit(void);
void MTOS_open_pipe(void);
extern int aesid;
#endif
RETSIGTYPE inter(anint)
int anint;
{
#ifdef OS2
(void) signal(anint, SIG_ACK);
#else
(void) signal(SIGINT, (sigfunc) inter);
#endif
#ifndef DOSX286
(void) signal(SIGFPE, SIG_DFL); /* turn off FPE trapping */
#endif
#ifdef OS2
PM_intc_cleanup();
#else
term_reset();
(void) putc('\n', stderr);
longjmp(command_line_env, TRUE); /* return to prompt */
#endif
}
#ifdef LINUXVGA
/* utility functions to ensure that setuid gnuplot
* assumes root privileges only for those parts
* of the code which require root rights.
*
* By "Dr. Werner Fink" <werner@suse.de>
*/
static uid_t euid, ruid;
static gid_t egid, rgid;
static int asked_privi = 0;
void
drop_privilege()
{
if (!asked_privi) {
euid = geteuid();
egid = getegid();
ruid = getuid();
rgid = getgid();
asked_privi = 1;
}
if (setegid(rgid) == -1)
(void) fprintf(stderr, "setegid(%d): %s\n",
(int) rgid, strerror(errno));
if (seteuid(ruid) == -1)
(void) fprintf(stderr, "seteuid(%d): %s\n",
(int) ruid, strerror(errno));
}
void
take_privilege()
{
if (!asked_privi) {
euid = geteuid();
egid = getegid();
ruid = getuid();
rgid = getgid();
asked_privi = 1;
}
if (setegid(egid) == -1)
(void) fprintf(stderr, "setegid(%d): %s\n",
(int) egid, strerror(errno));
if (seteuid(euid) == -1)
(void) fprintf(stderr, "seteuid(%d): %s\n",
(int) euid, strerror(errno));
}
#endif /* LINUXVGA */
/* a wrapper for longjmp so we can keep everything local */
void bail_to_command_line()
{
longjmp(command_line_env, TRUE);
}
#if defined(_Windows) || defined(_Macintosh)
int gnu_main(argc, argv)
#else
int main(argc, argv)
#endif
int argc;
char **argv;
{
#ifdef LINUXVGA
LINUX_setup();
#endif
/* make sure that we really have revoked root access, this might happen if
gnuplot is compiled without vga support but is installed suid by mistake */
#ifdef __linux__
setuid(getuid());
#endif
#if defined(MSDOS) && !defined(_Windows) && !defined(__GNUC__)
PC_setup();
#endif /* MSDOS !Windows */
/* HBB: Seems this isn't needed any more for DJGPP V2? */
/* HBB: disable all floating point exceptions, just keep running... */
#if defined(DJGPP) && (DJGPP!=2)
_control87(MCW_EM, MCW_EM);
#endif
#if defined(OS2)
int rc;
if (_osmode == OS2_MODE) {
PM_setup();
rc = RexxRegisterSubcomExe("GNUPLOT", (PFN) RexxInterface, NULL);
}
#endif
/* malloc large blocks, otherwise problems with fragmented mem */
#ifdef OSK
_mallocmin(102400);
#endif
#ifdef MALLOCDEBUG
malloc_debug(7);
#endif
/* get helpfile from home directory */
#ifndef DOSX286
# ifndef _Windows
# if defined (__TURBOC__) && (defined (MSDOS) || defined(DOS386))
strcpy(HelpFile, argv[0]);
strcpy(strrchr(HelpFile, DIRSEP1), "\\gnuplot.gih");
# endif /* - DJL */
# endif /* !_Windows */
#endif /* !DOSX286 */
#ifdef __DJGPP__
{
char *s;
strcpy(HelpFile, argv[0]);
for (s = HelpFile; *s; s++)
if (*s == DIRSEP1)
*s = DIRSEP2; /* '\\' to '/' */
strcpy(strrchr(HelpFile, DIRSEP2), "/gnuplot.gih");
} /* Add also some "paranoid" tests for '\\': AP */
#endif /* DJGPP */
#ifdef VMS
unsigned int status[2] = { 1, 0 };
#endif
#ifdef HAVE_LIBREADLINE
rl_readline_name = argv[0];
rl_complete_with_tilde_expansion = 1;
#endif
#ifdef X11
{
int n = X11_args(argc, argv);
argv += n;
argc -= n;
}
#endif
#ifdef apollo
apollo_pfm_catch();
#endif
/* moved to ATARI_init in atariaes.trm */
/* #ifdef ATARI
void application_init(void);
application_init();
#endif */
#ifdef MTOS
MTOS_open_pipe();
#endif
setbuf(stderr, (char *) NULL);
#ifndef NO_SETVBUF
/* this was once setlinebuf(). Docs say this is
* identical to setvbuf(,NULL,_IOLBF,0), but MS C
* faults this (size out of range), so we try with
* size of 1024 instead. [SAS/C does that, too. -lh]
* Failing this, I propose we just make the call and
* ignore the return : its probably not a big deal
*/
if (setvbuf(stdout, (char *) NULL, _IOLBF, (size_t) 1024) != 0)
fputs("Could not linebuffer stdout\n", stderr);
#endif
gpoutfile = stdout;
(void) Gcomplex(&udv_pi.udv_value, Pi, 0.0);
init_memory();
interactive = FALSE;
init_terminal(); /* can set term type if it likes */
#ifdef AMIGA_SC_6_1
if (IsInteractive(Input()) == DOSTRUE)
interactive = TRUE;
else
interactive = FALSE;
#else
# if (defined(__MSC__) && defined(_Windows)) || defined(__WIN32__)
interactive = TRUE;
# else
interactive = isatty(fileno(stdin));
# endif
#endif /* !AMIGA_SC_6_1 */
if (argc > 1)
interactive = noinputfiles = FALSE;
else
noinputfiles = TRUE;
if (interactive)
show_version(stderr);
#ifdef VMS
/* initialise screen management routines for command recall */
if (status[1] = smg$create_virtual_keyboard(&vms_vkid) != SS$_NORMAL)
done(status[1]);
if (status[1] = smg$create_key_table(&vms_ktid) != SS$_NORMAL)
done(status[1]);
#endif /* VMS */
if (!setjmp(command_line_env)) {
/* first time */
interrupt_setup();
load_rcfile();
init_fit(); /* Initialization of fitting module */
if (interactive && term != 0) /* not unknown */
fprintf(stderr, "\nTerminal type set to '%s'\n", term->name);
} else {
/* come back here from int_error() */
if (interactive == FALSE)
exit_status = EXIT_FAILURE;
#ifdef AMIGA_SC_6_1
(void) rawcon(0);
#endif
load_file_error(); /* if we were in load_file(), cleanup */
#ifdef _Windows
SetCursor(LoadCursor((HINSTANCE) NULL, IDC_ARROW));
#endif
#ifdef VMS
/* after catching interrupt */
/* VAX stuffs up stdout on SIGINT while writing to stdout,
so reopen stdout. */
if (gpoutfile == stdout) {
if ((stdout = freopen("SYS$OUTPUT", "w", stdout)) == NULL) {
/* couldn't reopen it so try opening it instead */
if ((stdout = fopen("SYS$OUTPUT", "w")) == NULL) {
/* don't use int_error here - causes infinite loop! */
fputs("Error opening SYS$OUTPUT as stdout\n", stderr);
}
}
gpoutfile = stdout;
}
#endif /* VMS */
if (!interactive && !noinputfiles) {
term_reset();
#if defined(ATARI) || defined(MTOS)
if (aesid > -1)
atexit(appl_exit);
#endif
return (IO_ERROR); /* exit on non-interactive error */
}
}
if (argc > 1) {
#ifdef _Windows
int noend = 0;
#endif
/* load filenames given as arguments */
while (--argc > 0) {
++argv;
c_token = NO_CARET; /* in case of file not found */
#ifdef _Windows
if (stricmp(*argv, "-noend") == 0 || stricmp(*argv, "/noend") == 0)
noend = 1;
else
#endif
if (strcmp(*argv, "-") == 0) {
/* DBT 10-7-98 go interactive if "-" on command line */
interactive = TRUE;
/* will this work on all platforms? */
while (!com_line());
/* interactive = FALSE; */ /* should this be here? */
} else
load_file(fopen(*argv, "r"), *argv, FALSE);
}
#ifdef _Windows
if (noend) {
interactive = TRUE;
while (!com_line());
}
#endif
} else {
/* take commands from stdin */
while (!com_line());
}
term_reset();
#ifdef OS2
if (_osmode == OS2_MODE)
RexxDeregisterSubcom("GNUPLOT", NULL);
#endif
#if defined(ATARI) || defined(MTOS)
if (aesid > -1)
atexit(appl_exit);
#endif
return (exit_status);
}
#if (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
int purec_matherr(struct exception *e)
{
char *c;
switch (e->type) {
case DOMAIN:
c = "domain error";
break;
case SING:
c = "argument singularity";
break;
case OVERFLOW:
c = "overflow range";
break;
case UNDERFLOW:
c = "underflow range";
break;
default:
c = "(unknown error";
break;
}
fprintf(stderr, "\
math exception : %s\n\
name : %s\n\
arg 1: %e\n\
arg 2: %e\n\
ret : %e\n",
c,
e->name,
e->arg1,
e->arg2,
e->retval);
return 1;
}
#endif /* (ATARI || MTOS) && PUREC */
/* Set up to catch interrupts */
void interrupt_setup()
{
#ifdef __PUREC__
setmatherr(purec_matherr);
#endif
(void) signal(SIGINT, (sigfunc) inter);
#ifdef SIGPIPE
/* ignore pipe errors, this might happen with set output "|head" */
(void) signal(SIGPIPE, SIG_IGN);
#endif /* SIGPIPE */
}
/* Look for a gnuplot init file in . or home directory */
static void load_rcfile()
{
FILE *plotrc = NULL;
char home[80];
char rcfile[sizeof(PLOTRC) + 80];
char *tmp_home = NULL;
#ifndef VMS
char *p; /* points to last char in home path, or to \0, if none */
tmp_home = getenv(HOME);
if (tmp_home) {
safe_strncpy(home, tmp_home, sizeof(home));
if (strlen(home))
p = &home[strlen(home) - 1];
else
p = home;
if ((*p != DIRSEP1) && (*p != DIRSEP2) && (*p != NUL)) {
assert(p >= home && p <= (home + sizeof(home) - 1 - 2));
if (*p)
p++;
*p++ = DIRSEP1;
*p = NUL;
}
}
#else /* VMS */
safe_strncpy(home, HOME, sizeof(home));
tmp_home = home;
#endif /* VMS */
#ifdef NOCWDRC
/* inhibit check of init file in current directory for security reasons */
#else
(void) strcpy(rcfile, PLOTRC);
plotrc = fopen(rcfile, "r");
#endif /* !NOCWDRC */
if (plotrc == NULL) {
if (tmp_home) {
(void) sprintf(rcfile, "%s%s", home, PLOTRC);
plotrc = fopen(rcfile, "r");
#if defined(ATARI) || defined(MTOS)
if (plotrc == NULL) {
char const *const ext[] = { NULL };
char *ini_ptr = findfile(PLOTRC, getenv("GNUPLOTPATH"), ext);
if (ini_ptr)
plotrc = fopen(ini_ptr, "r");
}
#endif /* ATARI || MTOS */
}
}
if (plotrc)
load_file(plotrc, rcfile, FALSE);
}
#ifdef OS2
int ExecuteMacro(char *argv, int namelength)
{
RXSTRING rxRc;
RXSTRING rxArg;
char pszName[CCHMAXPATH];
short sRc;
int rc;
safe_strncpy(pszName, argv, sizeof(pszName));
MAKERXSTRING(rxArg, argv, strlen(argv));
rc = RexxStart(1,
&rxArg,
pszName,
NULL,
"GNUPLOT",
RXCOMMAND,
NULL,
&sRc,
&rxRc);
if (rc == -4)
rc = 0; /* run was cancelled-don't give error message */
/* We don't use this value ?
BTW, don't use free() instead since it's allocated inside RexxStart() */
DosFreeMem(rxRc.strptr);
return rc;
}
ULONG RexxInterface(PRXSTRING rxCmd, PUSHORT pusErr, PRXSTRING rxRc)
/*
** Rexx command line interface
*/
{
int rc;
static jmp_buf keepenv;
int cmdlen;
memcpy(keepenv, command_line_env, sizeof(jmp_buf));
if (!setjmp(command_line_env)) {
/* set variable input_line.
* Watch out for line length of NOT_ZERO_TERMINATED strings ! */
cmdlen = rxCmd->strlength + 1;
safe_strncpy(input_line, rxCmd->strptr, cmdlen);
input_line[cmdlen] = NUL;
rc = do_line();
*pusErr = RXSUBCOM_OK;
rxRc->strptr[0] = rc + '0';
rxRc->strptr[1] = NUL;
rxRc->strlength = strlen(rxRc->strptr);
} else {
*pusErr = RXSUBCOM_ERROR;
RexxSetHalt(getpid(), 1);
}
memcpy(command_line_env, keepenv, sizeof(jmp_buf));
return 0;
}
#endif